/*
 * Clase que instancia objetos que almacena los datos del usuario como 
 * jugador, inicializa sus entidades de acuerdo a la raza escogida y
 * contiene operaciones que permiten comunicar a la interfaz con la parte
 * logica del juego (Funciona como patrón de diseño Facade).
 */
package jugador;

import fuente.Terreno;
import fuente.MetropolisSingleton;
import fuente.Mezquita;
import fuente.Unidades;
import fuente.estructuras.*;
import java.awt.Dimension;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import servclien.ClientGUI;
import servclien.ServerGUI;


public class Jugador {
    
    private String _nombreJugador,
                   _raza;
    
    private int _nivel,
                _cantidadMinerales;
    
    private static DLL _listaUnidades;
    private static SLL _listaMezquitas;
    private static Terreno _mapa;

    /**
     * Constructor, Inicializa el jugador sin una raza ni nombres definidos, 
     * solamente con el terreno elegido.
     */
    public Jugador () throws ParserConfigurationException, 
                             SAXException, IOException {
        _listaMezquitas = new SLL();
        _listaUnidades = new DLL();
        
            
        _nombreJugador = "";
        _raza = "";
        _nivel = 1;
        _cantidadMinerales = 7000;
    }
    
    /**
     * Constructor de la clase, Recibe un Nombre del jugador
     * y el nombre de la raza para utilizar por el mismo, 
     * ambos DISTINTOS de nulo.
     * @param pNombreJugador Nombre del jugador
     * @param pRaza Nombre de la raza elegida por el jugador
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws IOException 
     */
    public Jugador(String pNombreJugador, String pRaza, String pMapa) throws ParserConfigurationException, 
                                                                             SAXException, IOException {
        _mapa = new Terreno (pMapa);
        MetropolisSingleton.getInstance(pNombreJugador);
        _nombreJugador = pNombreJugador;
        _raza = pRaza;
        _listaMezquitas = new SLL();
        _listaUnidades = new DLL();
        int conta=0;
        while (conta<5) {            
            _listaUnidades.insertar(new Unidades (_raza, "Peon", _nivel));
            _listaUnidades.insertar(new Unidades (_raza, "Escolta", _nivel));
            conta++;
        }
        _nivel = 1;
        _cantidadMinerales = 0;        
    }
    
    /**
     * Verifica el costo en minerales que tiene un cierto nivel, usado
     * por el metodo subir nivel() para verificar si se puede subir de nivel
     * al jugador o no de acuerdo al costo que conlleva el nivel.
     * @param pNivel Nivel para verificar su costo
     * @return El costo del nivel
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws IOException 
     */
    private int getCostoNivel (int pNivel) throws ParserConfigurationException, 
                                                  SAXException, IOException {
        DocumentBuilderFactory docBF = DocumentBuilderFactory.newInstance();
        DocumentBuilder docB = docBF.newDocumentBuilder();
        org.w3c.dom.Document doc = docB.parse(new File("src/xml/Unidades.xml"));
        
        doc.getDocumentElement().normalize();
        
        NodeList nivelesLista = doc.getElementsByTagName("Nivel");
        for (int i  = 0; i < nivelesLista.getLength(); i++) {
            Node nivel = nivelesLista.item(i);
            Element eNivel = (Element)(nivel);
            
            int niv = Integer.parseInt(eNivel.getAttribute("Numero"));
            
            if (niv == pNivel) {
                int costo = Integer.parseInt(eNivel.getAttribute("Costo"));
                
                return costo;
            }
            else {
            }
        }
        return 0;
    }
    
    /* Inicio implementacion de getters y setters */
    /**
     * Retorna el nombre del usuario.
     * @return El nombre del jugador.
     */
    public String getNombreJugador() {
        return _nombreJugador;
    }
    
    /**
     * Retorna el nombre de la raza elegida por el usuario.
     * @return La raza elegida del jugador.
     */
    public String getRaza() {
        return _raza;
    }
    
    /**
     * Retorna el nivel en el que se encuentra el jugador en el momento.
     * @return El nivel que posee el jugador.
     */
    public int getNivel() {
        return _nivel;
    }
    
    /**
     * Establece el nombre del jugador.
     * @param pNombreJugador El nombre del jugador.
     */
     public void setNombreJugador(String pNombreJugador) {
        this._nombreJugador = pNombreJugador;
    }
     
    /**
     * Retorna la lista doblemente enlazada que contiene las unidades creadas
     * @return La lista de unidades del jugador 
     */
    public static DLL getListaUnidades () {
        return _listaUnidades;
    }
     
    /**
     * Establece el nombre de la raza elegida por el usuario.
     * @param pRaza el nombre de la raza elegida por el jugador.
     */
    public void setRaza (String pRaza) {
        this._raza = pRaza;
    }
    
    /**
     * Establece el numero de nivel del jugador.
     * @param pNivel el nivel adquirido por el jugador.
     */
    public void setNivel (int pNivel) {
        this._nivel = pNivel;
    }
    
    /**
     * Retorna la lista simple enlazada que contiene las mezquitas creadas.
     * @return La lista de mezquitas que tiene creadas el jugador
     */
    public SLL getListaMezquitas () {
        return _listaMezquitas;
    }
    
    /**
     * Inicializa el objeto jugador con sus unidades iniciales de peones
     * y escoltas modificados de acuerdo a la raza escogida por el
     * usuario.
     * @param pRaza Raza seleccionada
     * @param pNombre Nombre del usuario
     */
    public void set_Inicializar (String pRaza, String pNombre, String pMapa) throws ParserConfigurationException, 
                                                                                    SAXException, IOException {
        if (_nombreJugador.equals("")) {
            MetropolisSingleton.getInstance(pNombre);
            _mapa = new Terreno(pMapa);
            _nombreJugador = pNombre;
            _raza = pRaza;
            int conta = 0;
            while (conta < 5) {
                _listaUnidades.insertar(new Unidades (_raza, "Peon", _nivel));
                _listaUnidades.insertar(new Unidades (_raza, "Escolta", _nivel));
                conta++;
            }
        }
        else {
            System.out.println("Jugador ya ha sido inicializado");
        }
    }
    /* Final implementacion de getters y setters */
    
    /**
     * Verifica si se puede subir de nivel, si se puede lo hace y
     * disminuye los minerales que costo dicho nivel, si no, no lo hace.Retorna
     * true a la GUI si se puede para que realice los cambios en la parte grafica
     * respectivos, y false si no se puede subir para que no haga cambios.
     * @param pNivel Nivel a verificar
     * @return true si sube de nivel, false si no lo hace
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws IOException 
     */
    public boolean subirNivel (String pNivel) throws ParserConfigurationException, 
                                                  SAXException, IOException {
        int nivel = Integer.parseInt(pNivel);
        int costoNivel = getCostoNivel(nivel);
        
        if (costoNivel <= _cantidadMinerales) {
            _nivel = nivel;
            _cantidadMinerales -= costoNivel;
            return true;
        }
        else {
            return false;
        }
    }
    
        /**
     * Crea una unidad a partir del nombre de unidad seleccionado
     * @param pUnidad_A_Crear Unidad que se desea crear para el jugador
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws IOException 
     */
    public void crearUnidad (String pUnidad_A_Crear) throws ParserConfigurationException, 
                                                           SAXException, IOException {
        
        Unidades tmp = new Unidades (_raza, pUnidad_A_Crear, _nivel);
        if (_cantidadMinerales < tmp.getCosto()) {
            
        }
        else {
            _cantidadMinerales -= tmp.getCosto();
            _listaUnidades.insertar(new Unidades (_raza, pUnidad_A_Crear, _nivel));
        }
    }
     
    /**
     * Elimina una Unidad de la lista de Unidades del jugador.
     * @param pUnidad Unidad a buscar y eliminar
     */
    public void eliminarUnidad (Unidades pUnidad){
       int pos= _listaUnidades.buscarYDarPosicion(pUnidad);
       if (pos==0){
           System.out.println("No existe la Unidad a eliminar");
       }
       else{
           _listaUnidades.eliminaPorPosicion(pos);
       }
    }
    
    /**
     * Crea una mezquita y la inserta en la lista de mezquitas.
     */
    public void crearMezquita () {
        _listaMezquitas.meterFinal(new Mezquita());
        
    }
    
     /**
     * Elimina una mezquita de la lista de mezquitas.
     */
    public void eliminarMezquita (Mezquita pMezquita){
        int pos= _listaMezquitas.buscarYDarPosicion(pMezquita);
        _listaMezquitas.eliminaPorPosicion(pos);
    }
    
    /**
     * Actualiza la cantidad total de minerales, buscando lo que se ha añadido en el 
     * momento en la metropolis y cada mezquita de la lista de Mezquitas del jugador,
     * y establece en cero los minerales de cada mezquita y la metropolis una vez
     * actualizados.
     */
    public void actualizarMinerales () {
        _cantidadMinerales += MetropolisSingleton.getInstance(_nombreJugador).getCantidadDeMinerales();
        MetropolisSingleton.getInstance(_nombreJugador).setCantidadMinerales(0);
        
        for (SLLNode n = _listaMezquitas.getHead(); n != null; n = n.getNext()) {
            Mezquita tmp = (Mezquita) n.getElemento();
            _cantidadMinerales += tmp.getCantidadMinerales();
            tmp.setCantidadMinerales(0);
        }
    }
    
    /**
     * Busca y lee la imagen del xml del terreno elegido para mostrarla.
     * @param pMapa Nombre del terreno elegido por el usuario
     * @return La ruta de la imagen del terreno
     */
    public String getRutaImagenTerreno (String pMapa) throws ParserConfigurationException, 
                                                        SAXException, IOException {
        DocumentBuilderFactory docBF = DocumentBuilderFactory.newInstance();
        DocumentBuilder docB = docBF.newDocumentBuilder();
        org.w3c.dom.Document doc = docB.parse(new File("src/xml/Mapa/"+pMapa));
        
        doc.getDocumentElement().normalize();
        
        NodeList ListaNodoImagen = doc.getElementsByTagName("Imagen");
        
        Node NodoImagen = ListaNodoImagen.item(0);
        Element eImagen = (Element)(NodoImagen);
        
        String path = eImagen.getTextContent();
        return path;
    }
    
    public void servidor(){
        ServerGUI.main(new String[0]);
    }
    
    public void cliente(){
        ClientGUI.main(new String[0]);
    }
    
//    public Dimension setDimension(int width, int height){
//        Dimension dism = new Dimension();
//        if (width >= 500 && height >= 500){
//            dism.setSize(width, height);
//            return dism;
//        }
//        else
//            dism.setSize(500, 500);
//            return dism;
//    }
    
}
